package com.sk.ccflower.server.lib.sockUtils.nio;

import java.nio.channels.SocketChannel;

public class SocketSession extends NioSession implements Runnable
{
	protected final SocketServer m_server;
	private Thread m_thread = null;

	public SocketSession(SocketChannel sc, SocketServer server) throws Exception
	{
		super(sc, server.getSelector());
		
		m_server = server;
		m_sc.configureBlocking(false);

		try {
			doConnectAction();
		} catch (Exception e) {
			m_log.debug(m_sc.socket().getInetAddress().getHostAddress() + ":" + m_sc.socket().getPort() + " doConnectAction()의 exception발생으로 접속 종료", e);
			try {
				m_sc.close();
			} catch(Exception ex) {
			}
			throw e;
		}

		registerHandler();

		m_log.debug(m_sc.socket().getInetAddress().getHostAddress() + ":" + m_sc.socket().getPort() + " 클라이언트 접속");
	}
	
	public SocketSession(SocketChannel sc, NioSelector selector) throws Exception
	{
		super(sc, selector);
		m_server = null;
	}
	
	public SocketSession(SocketChannel sc) throws Exception
	{
		super(sc);
		m_server = null;
	}
	
	public void close()
	{
		super.close();
		if(m_thread!=null && m_selector!=null) m_selector.endSelect();
	}
	
	public SocketServer setSocketServer()
	{
		return m_server;
	}

	/**
	 * 세션을 thread mode로 구동 시키고자 할때 호출한다. - selector를 내부적으로 생성하여 관리
	 */
	public void startThread() throws Exception
	{
		if(m_thread!=null) return;

		NioSelector selector = null;
		
		try
		{
			selector = new NioSelector();
			startThread(selector);
		}
		catch (Exception e)
		{
			selector.close();
			throw e;
		}
	}

	/**
	 * 세션을 thread mode로 구동 시키고자 할때 호출한다. - 입력된 selector를 이용하여 관리
	 */
	public void startThread(NioSelector selector) throws Exception
	{
		if(m_thread!=null) return;
		if(selector==null)	throw new Exception("selector가 null입니다.");

		try
		{
			registerHandler(selector);
			
			m_thread = new Thread(this);
			m_thread.start();
		}
		catch (Exception e)
		{
			close();

			if(m_selector!=null) m_selector.close();

			m_selector = null;
			m_thread = null;

			throw new Exception("startThread error: " + e.getMessage(), e);
		}
		
	}

	/**
	 * thread mode에서 호출되는 run() method
	 */
	public void run()
	{
		try
		{
			m_selector.run();
		}
		catch (Exception e)
		{
			m_log.error("thread run error: " + e.getMessage(), e);
		}
		finally
		{
			m_selector.close();

			m_selector = null;
			m_thread = null;
		}
	}
}
